﻿using System;
using System.Collections.Generic;
using System.Text;
using Core.Domain;
using Core.Domain.Lexems;

namespace Core.SyntaxAnalysis.Classes
{
    public class FOR : Stmt
    {
        private readonly Stmt m_body;
        private readonly Expr m_endvalue;
        private readonly Stmt m_initialization;
        private readonly Lexem m_lex;

        /// <summary>
        /// for i := 7 to 54 do x := x + 7;
        /// </summary>
        /// <param name="initialization"> I := 7</param>
        /// <param name="lex"> TO / DOWNTO </param>
        /// <param name="endvalue"> 54 </param>
        /// <param name="body"> x := x + 7; </param>
        public FOR(Stmt initialization, Lexem lex, Expr endvalue, Stmt body)
        {
            m_initialization = initialization;
            m_lex = lex;
            m_endvalue = endvalue;
            m_body = body;
        }

        public override bool StmtSemanticCheck(ref List<CompilerError> errors)
        {
            bool error = false;
            Assign init = null;
            if (!m_initialization.SemanticCheck(ref errors))
            {
                error = true;
            }
            if (!error)
            {
                try
                {
                    init = (Assign) m_initialization;
                }
                catch (InvalidCastException)
                {
                    errors.Add(new CompilerError(errors.Count + 1, Resources.NoVariabledInitInForHeaderErrorMessage, m_lex));
                    error = true;
                }
                if (!error)
                {
                    DataType leftType = init.GetTypeOfLeftSide();
                    if (leftType.TypeId() < 0)
                    {
                        errors.Add(new CompilerError(errors.Count + 1, Resources.WrongDataTypeInForHeaderErrorMessage, m_lex));
                        error = true;
                    }
                    else
                    {
                        DataType rightType = m_endvalue.GetExprType();
                        if (rightType.TypeId() != leftType.TypeId())
                        {
                            error = true;
                            errors.Add(new CompilerError(errors.Count + 1, Resources.TypeOfLoopVariableDoesNotMatchTypeOfTheEndValueErrorMessage, m_lex));
                        }
                        else if (!m_body.SemanticCheck(ref errors))
                        {
                            error = true;
                        }
                    }
                }
            }
            return !error;
        }

        public override void StmtGenerate(StringBuilder s)
        {
            m_initialization.StmtGenerate(s);
            int loopLabel = Env.NextLabel();
            int afterLoopLabel = Env.NextLabel();

            var init = (Assign) m_initialization;
            CodeGenerator.AppendLabel(s, loopLabel);
            CodeGenerator.AppendIfNotGoto(s, init.Left.StrValue + " < " + m_endvalue.Generate(s), afterLoopLabel);
            m_body.Generate(s);
            CodeGenerator.AppendIncrement(s, init.Left.StrValue);
            CodeGenerator.AppendGoto(s, loopLabel);
            CodeGenerator.AppendLabel(s, afterLoopLabel);
        }
    }
}